An algorithm to find the last nonzero digit of n!
=================================================

(W. Bomfim)


    The problem of find the last nonzero digit of n! received the attention of
several authors. From OEIS sequence A008904 we can see several works. The
answers of exercises 40, and 54 of [1] give a clear method to solve this problem
for the particular case n=1000. It appears that nobody tried to generalize this
method to write an algorithm to determine this digit for a given value of n.
Here we will see a way to do that.


I - A generalization of the theory found in exercises 40, and 54
----------------------------------------------------------------


Let
    n be an integer, n >= 2,
    M_5(n) be the multiplicity of 5 in the factorization of n!, and
    M_2(n) be the multiplicity of 2 in the factorization of n!.

    Substituting p for 5 in a congruence found in Concrete Mathematics, [1], we
have

   n!
-------- == (-l)^M_5(n) * a_h!...a_1!a_0!  (mod 5)                           (1)
5^M_5(n)

where (a_h ... a_1 a_0)5 is the radix 5 representation of n.

Hence M_2(n) > M_5(n), see LEMMA 1,

               n!               2^M_5(n)
multiplying -------- in (1) by  -------- , we have
            5^M_5(n)            2^M_5(n)

    n!
----------------- 2^M_5(n)  == (-l)^M_5(n) * a_h!...a_1!a_0!  (mod 5)        (2)
5^M_5(n).2^M_5(n)

By  LEMMA 1 n! is divisible by 5^M_5(n).2^M_5(n) = 10^M_5(n), and n! is not
divisible by 10^(M_5(n) + a), a >= 1. So the expression

       n!
-----------------
5^M_5(n).2^M_5(n)


which we will denote below by I, is equal to the integer formed by all the
initial digits of n!, except the trailing zeros of n!. It follows that the last
digit of I, i.e., I mod 10, is equal to the final non-zero digit of n!. First we
will determine I mod 5. From I mod 5 it will be easy to find I mod 10.

    From (2) we get

I.2^M_5(n)  == (-l)^M_5(n) * a_h!...a_1!a_0!  (mod 5)                        (3)

let m = M_5(n) mod 4.

By  LEMMA 2 below, (3) becomes,

I.2^m  == (-l)^M_5(n) * a_h!...a_1!a_0!  (mod 5) .

Since the parity of M_5(n) is equal to the parity of m, we get

I.2^m  == (-l)^m * a_h!...a_1!a_0!  (mod 5).                                 (4)

With P = (a_h!...a_1!a_0!) mod 5, it follows that

P == (a_h! mod 5)...(a_1! mod 5)(a_0! mod 5)  (mod 5)

and P == 2^(t/2) (mod 5) , t the sum of the even a_i's, i = 0,1,..., h.      (5)

(5) is true because if a_i is odd, i.e. , a_i = 1, or a_i = 3, a_i! mod 5 = 1;
hence for each even a_i, a_i! mod 5 is equal to 2^(a_i/2), P == 2^(t/2) (mod 5).

Then from (4) and (5),

I.2^m  == (-l)^m * 2^(t/2)  (mod 5),                                         (6)


Naturally t/2 == (t/2) mod 4 (mod 4). By LEMMA 2 below, (6) gives

I.2^m  == (-l)^m * 2^((t/2) mod 4) (mod 5).

With i = I mod 5 ,

we get

i.2^m == (-l)^m * 2^((t/2) mod 4)  (mod 5).                                  (7)

Let L be the last nonzero digit of n!.

     From LEMMA 1, M_2(n) > M_5(n) so L is always even. By LEMMA 3, because L =
I mod 10, L = i, or L = i+5.  We conclude that if i is odd, L = i + 5, and if i
is even, L = i.

    Since both m, and (t/2) mod 4, have values from 0 to 3, (7) can be written
only in the ways depicted in the following table.


+---+------+-----+------------------------------------------------+---+-------+
|   |      |(t/2)|                                                |   |       |
| m |(-1)^m|mod 4| i.2^m == (-l)^m * 2^((t/2) mod 4) (mod 5)  (7) | i |   L   |
+---+------+-----+------------------------------------------------+---+-------+
| 0 |   1  |  0  | i == 2^0 (mod 5)                               | 1 |1+5 = 6|
|   |      |  1  | i == 2^1 (mod 5)                               | 2 |      2|
|   |      |  2  | i == 2^2 (mod 5)                               | 4 |      4|
|   |      |  3  | i == 2^3 (mod 5)                               | 3 |3+5 = 8|
+---+------+-----+------------------------------------------------+---+-------+
| 1 |  -1  |  0  | 2i == -2^0, 2i == -1, 2i == 4, i == 2 (mod 5)  | 2 |      2|
|   |      |  1  | 2i == -2^1, 2i == -2, i == -1 (mod 5)          | 4 |      4|
|   |      |  2  | 2i == -2^2, 2i == -4, i == -2 (mod 5)          | 3 |      8|
|   |      |  3  | 2i == -2^3, 2i == -8, i == -4 (mod 5)          | 1 |      6|
+---+------+-----+-------+----------------------------------------+---+-------+
| 2 |   1  |  0  | 4i == 2^0, 4i == 1, 4i == -4, i == -1 (mod 5)  | 4 |      4|
|   |      |  1  | 4i == 2^1, 2i == 1, 2i == 6, i == 3 (mod 5)    | 3 |      8|
|   |      |  2  | 4i == 2^2, 4i == 4, i == 1 (mod 5)             | 1 |      6|
|   |      |  3  | 4i == 2^3, 4i == 8, i == 2 (mod 5)             | 2 |      2|
+---+------+-----+-------+-------+--------------------------------+---+-------+
| 3 |  -1  |  0  | 8i == -2^0, 3i == -1, 3i == -6, i == -2 (mod 5)| 3 |      8|
|   |      |  1  | 8i == -2^1, 3i == -2, 3i == 3, i == 1 (mod 5)  | 1 |      6|
|   |      |  2  | 8i == -2^2, 3i == -4, 3i == 6, i == 2 (mod 5)  | 2 |      2|
|   |      |  3  | 8i == -2^3, 8i == -8, i == -1 (mod 5)          | 4 |      4|
+---+------+-----+------------------------------------------------+---+-------+

From the table above L can be determined by,

--------------------------------------
z <- (x + t/2) mod 4;
if z is 0, L <- 6, otherwise L <- 2^z.
--------------------------------------

where x == m (mod 4). For example, let x such that m = x mod 4 = 2, so (-1)^m =
1, and let t/2 mod 4 = 0; thus z = 2, and L = 4. We can see L=4 in line "2 1 0"
of the table above.



    The multiplicity M_5(n), [2], section 1.2.5, is given by

M_5(n) = [n/5^1] + [n/5^2] + [n/5^3] + ...                                   (8)

from LEMMA 4, for 1 <= k <= h, [n/5^k] == (a_h + ... + a_k) (mod 4) , so we can
find x such that x == m (mod 4), by

------------------------------------------------------
q <- 0;
for i = h, h-1, ... , 1, { q <- q + a_i; x <- x + q }.
------------------------------------------------------

    Because the variable q in the pseudo-code above, at the k-th iteration
receives the value of the sum (a_h + ... + a_k) , which is congruent to [n/5^k],
after the last iteration x is congruent to M_5(n), and also x is congruent to m
(mod 4).



II - The algorithm
------------------

Algorithm. Given an integer n, n>=0, find L equal to the last nonzero digit of
            n!.
1. [Check n >= 2.] If n = 0 or 1, the algorithm ends returning 1.
2. [Initialize.] Set q <- 0; t <- 0; x <- 0;
3. [Convert n to base 5.] Let s <- a_h, ... ,a_1,a_0 be the sequence of digits
                          of n in quinary.
4. [Scan digits.] For i = h, h-1, ... , 1, make q <- q + a_i; x <- x + q;
                  if a_i is even, set t <- t + a_i.
5. [Find L.] If a_0 is even, set t <- t + a_0. Set z <- (x + t/2) mod 4;
             if z is 0, make L <- 6, otherwise set L <- 2^z. The algorithm ends,
             L is the answer.
***

    From section I, it is easy to show that this algorithm is correct.

    The execution time of the given algorithm depends of the time needed to
execute step 3. When n is large, n can be converted in sub-quadratic time using
efficient multiple-precision packages. For example, I used the function
mpz_get_str() of GMP(MPIR), [3]. Step 4 runs in O(log n) time.
    We use O(log n) bytes to store the digits of (n)5 in a C string. It is
possible to find the digits one by one, from the MSD, which is all that the
presented algorithm needs, but I do not know how to do that efficiently. When
several values of n are given in a sequence, in some cases the conversion of n
can use previous results that make step 3 more efficient. I want to make
experiments in this direction.



III - The Lemmas
----------------

    The lemmas below make this presentation "self contained".


LEMMA 1. For n >= 2, M_2(n) > M_5(n).
    For n=2, 3, and 4, M_2(n) > M_5(n) since M_5(n) = 0. If n = 5, 5! =
2^3 * 3^1 * 5^1, so M_2(n) > M_5(n).
    When n = 6, 7, ... , we can write n as

    5k+1, 5k+2, 5k+3, 5k+4, 5(k+1); for k = 1,2, ... .

If k is even, 5k+2, and 5k+4 are both even, so as n takes the values 5k+1 to
5(k+1), M_2(n) increases at least three; M_5(n) increases at most two when
5(k+1) is a power of 5. The case odd k is similar.
***


LEMMA 2. Let x, and y be positive integers. If x==y (mod 4), 2^x == 2^y (mod 5).
    Because the last digit of 2^n takes the values 2, 4, 8, 6, 2, ... for n = 1,
2, ... , 2^x == 2^y (mod 10). LAW D of [2] section 1.2.4, with a = 2^x, b = 2^y,
rs = 10, r = 5, and s = 2 completes the proof.
***


LEMMA 3. If x mod 10 = r, x mod 5 = r, or r - 5.
    There is an integer k, k >= 0, such that x = 10k + r = 5k' + r, k' = 2k. If
r < 5 it follows immediately that x mod 5 = r. If r = 5 + a, 0=<a<=4, x= 5(k'+1)
+ a, so x mod 5 = a = r - 5. The proof is complete.

    Because x mod 10 = r => x mod 5 = r, or r - 5; we also have y mod 5 = R =>
y mod 10 = R, or R + 5.
***


LEMMA 4. Given a number n expressed in base 5 by a_h.5^h + ... + a_1.5^1 +
a_0.5^0 , [n/5^k] , for 1 <= k <= h, is congruent to (a_h + ... + a_k) (mod 4).

[n/5^k] = [ (a_h.5^h + ... a_1.5^1 + a_0.5^0) / 5^k ] =

a_h.5^(h-k) + ... + a_k.5^(k - k) = a_h.5^(h-k) + ... + a_k.

    The proof follows from the fact that for i >= 0, 5^i mod 4 = 1.
***



References
----------

[1] Ronald L. Graham, Donald E. Knuth and Oren Patashnik, Concrete Math.;
    Addison-Wesley, section 4, exercises 40, and 54.
[2] D. E. Knuth, The Art of Computer Programming, vol.1.
[3] http://www.mpir.org/mpir-1.3.1.pdf


